Modelo

source("../../lib/som-utils.R")

Attaching package: 'dplyr'
The following objects are masked from 'package:stats':

    filter, lag
The following objects are masked from 'package:base':

    intersect, setdiff, setequal, union
source("../../lib/maps-utils.R")
Linking to GEOS 3.8.0, GDAL 3.0.4, PROJ 6.3.1

Carga del modelo desde disco

mpr.set_base_path_analysis()
model <- mpr.load_model("som-369.rds.xz")
summary(model)
SOM of size 5x5 with a hexagonal topology and a bubble neighbourhood function.
The number of data layers is 1.
Distance measure(s) used: sumofsquares.
Training data included: 94881 objects.
Mean distance to the closest unit in the map: 0.05.
plot(model, type="changes")

Carga del dataset de entrada

df <- mpr.load_data("datos_mes.csv.xz")
df
summary(df)
 id_estacion           fecha             fecha_cnt           tmax      
 Length:94881       Length:94881       Min.   : 1.000   Min.   :-53.0  
 Class :character   Class :character   1st Qu.: 4.000   1st Qu.:148.0  
 Mode  :character   Mode  :character   Median : 6.000   Median :198.0  
                                       Mean   : 6.497   Mean   :200.2  
                                       3rd Qu.: 9.000   3rd Qu.:255.0  
                                       Max.   :12.000   Max.   :403.0  
      tmin             precip           nevada           prof_nieve      
 Min.   :-121.00   Min.   :  0.00   Min.   :0.000000   Min.   :   0.000  
 1st Qu.:  53.00   1st Qu.:  3.00   1st Qu.:0.000000   1st Qu.:   0.000  
 Median :  98.00   Median : 10.00   Median :0.000000   Median :   0.000  
 Mean   :  98.86   Mean   : 16.25   Mean   :0.000295   Mean   :   0.467  
 3rd Qu.: 148.00   3rd Qu.: 22.00   3rd Qu.:0.000000   3rd Qu.:   0.000  
 Max.   : 254.00   Max.   :422.00   Max.   :6.000000   Max.   :1834.000  
    longitud        latitud            altitud      
 Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:38.28   1st Qu.: -5.6417   1st Qu.:  42.0  
 Median :40.82   Median : -3.4500   Median : 247.0  
 Mean   :39.66   Mean   : -3.4350   Mean   : 418.5  
 3rd Qu.:42.08   3rd Qu.:  0.4914   3rd Qu.: 656.0  
 Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  

Carga de los mapas

world <- ne_countries(scale = "medium", returnclass = "sf")
spain <- subset(world, admin == "Spain")

Mapa de densidad

plot(model, type="count", shape = "straight", palette.name = mpr.degrade.bleu)

NĂºmero de elementos en cada celda:

nb <- table(model$unit.classif)
print(nb)

   1    2    3    4    5    6    7    8    9   10   11   12   13   14   15   16 
4183 5167 5420 2176  757 4626 4572 6068 4164 1948 3821 4133 5048 4378 3228 3091 
  17   18   19   20   21   22   23   24   25 
2975 3594 4850 5465 2715 3114 3384 2893 3111 

ComprobaciĂ³n de nodos vacĂ­os:

dim_model <- 5*5;
len_nb = length(nb);
empty_nodes <- dim_model != len_nb;
if (empty_nodes) {
  print(paste("[Warning] Existen nodos vacĂ­os: ", len_nb, "/", dim_model))
}

Mapa de distancia entre vecinos

plot(model, type="dist.neighbours", shape = "straight")

Influencia de las variables

model_colnames = c("tmax", "tmin")
model_ncol = length(model_colnames)

Mapa de variables.

plot(model, shape = "straight")

Mapa de calor por variable

par(mfrow=c(3,4))
for (j in 1:model_ncol) {
  plot(model, type="property", property=getCodes(model,1)[,j],
    palette.name=mpr.coolBlueHotRed,
    main=model_colnames[j],
    cex=0.5, shape = "straight")
}

CorrelaciĂ³n para cada columna del vector de nodos

if (!empty_nodes) {
  cor <- apply(getCodes(model,1), 2, mpr.weighted.correlation, w=nb, som=model)
  print(cor)
}
           tmax       tmin
[1,] -0.5150303 -0.7848423
[2,]  0.7210027  0.4158785

RepresentaciĂ³n de cada variable en un mapa de factores:

if (!empty_nodes) {
  par(mfrow=c(1,1))
  plot(cor[1,], cor[2,], xlim=c(-1,1), ylim=c(-1,1), type="n")
  lines(c(-1,1),c(0,0))
  lines(c(0,0),c(-1,1))
  text(cor[1,], cor[2,], labels=model_colnames, cex=0.75)
  symbols(0,0,circles=1,inches=F,add=T)
}

Importancia de cada variable - varianza ponderada por el tamaño de la celda:

if (!empty_nodes) {
  sigma2 <- sqrt(apply(getCodes(model,1),2,function(x,effectif)
     {m<-sum(effectif*(x-weighted.mean(x,effectif))^2)/(sum(effectif)-1)},
     effectif=nb))
  print(sort(sigma2,decreasing=T))
}
     tmin      tmax 
0.9875701 0.9874356 

Clustering

if (!empty_nodes) {
  hac <- mpr.hac(model, nb)
}

VisualizaciĂ³n de 3 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=3)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=3)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 87.0   Min.   :-31.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:156.0   1st Qu.: 60.00   1st Qu.:  6.00   1st Qu.:0  
 Median : 5.000   Median :175.0   Median : 78.00   Median : 15.00   Median :0  
 Mean   : 6.072   Mean   :176.9   Mean   : 77.81   Mean   : 20.89   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:197.0   3rd Qu.: 97.00   3rd Qu.: 28.00   3rd Qu.:0  
 Max.   :12.000   Max.   :265.0   Max.   :157.00   Max.   :371.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.: 0.00000   1st Qu.:38.37   1st Qu.: -5.6156   1st Qu.:  42  
 Median : 0.00000   Median :40.95   Median : -2.9056   Median : 143  
 Mean   : 0.04087   Mean   :40.25   Mean   : -2.9106   Mean   : 359  
 3rd Qu.: 0.00000   3rd Qu.:42.33   3rd Qu.:  0.4914   3rd Qu.: 609  
 Max.   :59.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2535  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 1.000   1st Qu.: 86.0   1st Qu.:  -3.00   1st Qu.:  6.00  
 Median : 3.000   Median :106.0   Median :  15.00   Median : 13.00  
 Mean   : 5.542   Mean   :100.7   Mean   :  12.16   Mean   : 20.25  
 3rd Qu.:11.000   3rd Qu.:122.0   3rd Qu.:  32.00   3rd Qu.: 27.00  
 Max.   :12.000   Max.   :199.0   Max.   :  76.00   Max.   :309.00  
     nevada           prof_nieve         longitud        latitud        
 Min.   :0.000000   Min.   :   0.00   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0.000000   1st Qu.:   0.00   1st Qu.:40.66   1st Qu.: -4.5353  
 Median :0.000000   Median :   0.00   Median :41.62   Median : -2.7331  
 Mean   :0.001583   Mean   :   2.41   Mean   :41.00   Mean   : -2.8208  
 3rd Qu.:0.000000   3rd Qu.:   0.00   3rd Qu.:42.38   3rd Qu.:  0.4483  
 Max.   :6.000000   Max.   :1834.00   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.: 459.0  
 Median : 704.0  
 Mean   : 862.9  
 3rd Qu.:1004.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin         precip            nevada 
 Min.   : 1.000   Min.   :173.0   Min.   : 57   Min.   :  0.000   Min.   :0  
 1st Qu.: 6.000   1st Qu.:240.0   1st Qu.:136   1st Qu.:  1.000   1st Qu.:0  
 Median : 7.000   Median :267.0   Median :157   Median :  5.000   Median :0  
 Mean   : 7.348   Mean   :268.4   Mean   :159   Mean   :  9.873   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:296.0   3rd Qu.:182   3rd Qu.: 14.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254   Max.   :422.000   Max.   :0  
   prof_nieve         longitud        latitud            altitud      
 Min.   : 0.0000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.: 0.0000   1st Qu.:37.18   1st Qu.: -6.0556   1st Qu.:  27.1  
 Median : 0.0000   Median :39.88   Median : -3.6781   Median :  85.0  
 Mean   : 0.0027   Mean   :38.48   Mean   : -4.2300   Mean   : 275.1  
 3rd Qu.: 0.0000   3rd Qu.:41.63   3rd Qu.:  0.3994   3rd Qu.: 534.0  
 Max.   :35.0000   Max.   :43.57   Max.   :  4.2156   Max.   :2371.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

VisualizaciĂ³n de 4 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=4)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=4)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 87.0   Min.   :-31.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:156.0   1st Qu.: 60.00   1st Qu.:  6.00   1st Qu.:0  
 Median : 5.000   Median :175.0   Median : 78.00   Median : 15.00   Median :0  
 Mean   : 6.072   Mean   :176.9   Mean   : 77.81   Mean   : 20.89   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:197.0   3rd Qu.: 97.00   3rd Qu.: 28.00   3rd Qu.:0  
 Max.   :12.000   Max.   :265.0   Max.   :157.00   Max.   :371.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.: 0.00000   1st Qu.:38.37   1st Qu.: -5.6156   1st Qu.:  42  
 Median : 0.00000   Median :40.95   Median : -2.9056   Median : 143  
 Mean   : 0.04087   Mean   :40.25   Mean   : -2.9106   Mean   : 359  
 3rd Qu.: 0.00000   3rd Qu.:42.33   3rd Qu.:  0.4914   3rd Qu.: 609  
 Max.   :59.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2535  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin             precip      
 Min.   : 1.000   Min.   :-53.0   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 1.000   1st Qu.: 86.0   1st Qu.:  -3.00   1st Qu.:  6.00  
 Median : 3.000   Median :106.0   Median :  15.00   Median : 13.00  
 Mean   : 5.542   Mean   :100.7   Mean   :  12.16   Mean   : 20.25  
 3rd Qu.:11.000   3rd Qu.:122.0   3rd Qu.:  32.00   3rd Qu.: 27.00  
 Max.   :12.000   Max.   :199.0   Max.   :  76.00   Max.   :309.00  
     nevada           prof_nieve         longitud        latitud        
 Min.   :0.000000   Min.   :   0.00   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0.000000   1st Qu.:   0.00   1st Qu.:40.66   1st Qu.: -4.5353  
 Median :0.000000   Median :   0.00   Median :41.62   Median : -2.7331  
 Mean   :0.001583   Mean   :   2.41   Mean   :41.00   Mean   : -2.8208  
 3rd Qu.:0.000000   3rd Qu.:   0.00   3rd Qu.:42.38   3rd Qu.:  0.4483  
 Max.   :6.000000   Max.   :1834.00   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.: 459.0  
 Median : 704.0  
 Mean   : 862.9  
 3rd Qu.:1004.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt          tmax            tmin         precip           nevada 
 Min.   : 1.00   Min.   :173.0   Min.   : 57   Min.   :  0.00   Min.   :0  
 1st Qu.: 6.00   1st Qu.:226.0   1st Qu.:127   1st Qu.:  3.00   1st Qu.:0  
 Median : 7.00   Median :246.0   Median :141   Median :  9.00   Median :0  
 Mean   : 7.18   Mean   :246.3   Mean   :140   Mean   : 13.15   Mean   :0  
 3rd Qu.: 9.00   3rd Qu.:267.0   3rd Qu.:156   3rd Qu.: 18.00   3rd Qu.:0  
 Max.   :12.00   Max.   :336.0   Max.   :195   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.: 0.00000   1st Qu.:37.26   1st Qu.: -6.2567   1st Qu.:  32  
 Median : 0.00000   Median :40.82   Median : -3.7892   Median :  98  
 Mean   : 0.00444   Mean   :38.93   Mean   : -4.5345   Mean   : 318  
 3rd Qu.: 0.00000   3rd Qu.:42.18   3rd Qu.:  0.0406   3rd Qu.: 609  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2371  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax            tmin         precip            nevada 
 Min.   : 2.000   Min.   :226.0   Min.   :111   Min.   :  0.000   Min.   :0  
 1st Qu.: 7.000   1st Qu.:280.0   1st Qu.:173   1st Qu.:  0.000   1st Qu.:0  
 Median : 8.000   Median :301.0   Median :188   Median :  1.000   Median :0  
 Mean   : 7.597   Mean   :300.9   Mean   :187   Mean   :  5.038   Mean   :0  
 3rd Qu.: 8.000   3rd Qu.:321.0   3rd Qu.:203   3rd Qu.:  6.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254   Max.   :320.000   Max.   :0  
   prof_nieve           longitud        latitud            altitud      
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:0.0000000   1st Qu.:36.85   1st Qu.: -5.8792   1st Qu.:  25.0  
 Median :0.0000000   Median :38.88   Median : -2.9553   Median :  68.6  
 Mean   :0.0001273   Mean   :37.82   Mean   : -3.7804   Mean   : 211.6  
 3rd Qu.:0.0000000   3rd Qu.:40.82   3rd Qu.:  0.4942   3rd Qu.: 412.0  
 Max.   :2.0000000   Max.   :43.56   Max.   :  4.2156   Max.   :1167.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

VisualizaciĂ³n de 5 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=5)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=5)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 87.0   Min.   :-31.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 3.000   1st Qu.:156.0   1st Qu.: 60.00   1st Qu.:  6.00   1st Qu.:0  
 Median : 5.000   Median :175.0   Median : 78.00   Median : 15.00   Median :0  
 Mean   : 6.072   Mean   :176.9   Mean   : 77.81   Mean   : 20.89   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:197.0   3rd Qu.: 97.00   3rd Qu.: 28.00   3rd Qu.:0  
 Max.   :12.000   Max.   :265.0   Max.   :157.00   Max.   :371.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.: 0.00000   1st Qu.:38.37   1st Qu.: -5.6156   1st Qu.:  42  
 Median : 0.00000   Median :40.95   Median : -2.9056   Median : 143  
 Mean   : 0.04087   Mean   :40.25   Mean   : -2.9106   Mean   : 359  
 3rd Qu.: 0.00000   3rd Qu.:42.33   3rd Qu.:  0.4914   3rd Qu.: 609  
 Max.   :59.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2535  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin            precip      
 Min.   : 1.000   Min.   : 20.0   Min.   :-80.00   Min.   :  0.00  
 1st Qu.: 1.000   1st Qu.: 89.0   1st Qu.: -1.00   1st Qu.:  5.00  
 Median : 3.000   Median :108.0   Median : 17.00   Median : 13.00  
 Mean   : 5.575   Mean   :104.8   Mean   : 15.14   Mean   : 19.43  
 3rd Qu.:11.000   3rd Qu.:123.0   3rd Qu.: 33.00   3rd Qu.: 26.00  
 Max.   :12.000   Max.   :199.0   Max.   : 76.00   Max.   :309.00  
     nevada           prof_nieve          longitud        latitud        
 Min.   :0.000000   Min.   :   0.000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0.000000   1st Qu.:   0.000   1st Qu.:40.66   1st Qu.: -4.6800  
 Median :0.000000   Median :   0.000   Median :41.59   Median : -3.1642  
 Mean   :0.001653   Mean   :   1.347   Mean   :40.95   Mean   : -2.9478  
 3rd Qu.:0.000000   3rd Qu.:   0.000   3rd Qu.:42.36   3rd Qu.:  0.3056  
 Max.   :6.000000   Max.   :1494.000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.: 445.0  
 Median : 687.0  
 Mean   : 804.8  
 3rd Qu.: 945.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax              tmin             precip      
 Min.   : 1.000   Min.   :-53.000   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 2.000   1st Qu.: -4.000   1st Qu.: -65.00   1st Qu.: 17.00  
 Median : 3.000   Median : 11.000   Median : -51.00   Median : 33.00  
 Mean   : 4.798   Mean   :  8.683   Mean   : -54.46   Mean   : 38.67  
 3rd Qu.:11.000   3rd Qu.: 23.000   3rd Qu.: -41.00   3rd Qu.: 54.00  
 Max.   :12.000   Max.   : 75.000   Max.   : -20.00   Max.   :180.00  
     nevada    prof_nieve         longitud        latitud         
 Min.   :0   Min.   :   0.00   Min.   :28.31   Min.   :-16.49920  
 1st Qu.:0   1st Qu.:   0.00   1st Qu.:42.18   1st Qu.:  0.73170  
 Median :0   Median :   0.00   Median :42.47   Median :  0.98440  
 Mean   :0   Mean   :  26.19   Mean   :42.12   Mean   :  0.01983  
 3rd Qu.:0   3rd Qu.:   0.00   3rd Qu.:42.64   3rd Qu.:  1.36560  
 Max.   :0   Max.   :1834.00   Max.   :42.85   Max.   :  2.43780  
    altitud    
 Min.   : 162  
 1st Qu.:1894  
 Median :2247  
 Mean   :2165  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt          tmax            tmin         precip           nevada 
 Min.   : 1.00   Min.   :173.0   Min.   : 57   Min.   :  0.00   Min.   :0  
 1st Qu.: 6.00   1st Qu.:226.0   1st Qu.:127   1st Qu.:  3.00   1st Qu.:0  
 Median : 7.00   Median :246.0   Median :141   Median :  9.00   Median :0  
 Mean   : 7.18   Mean   :246.3   Mean   :140   Mean   : 13.15   Mean   :0  
 3rd Qu.: 9.00   3rd Qu.:267.0   3rd Qu.:156   3rd Qu.: 18.00   3rd Qu.:0  
 Max.   :12.00   Max.   :336.0   Max.   :195   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.: 0.00000   1st Qu.:37.26   1st Qu.: -6.2567   1st Qu.:  32  
 Median : 0.00000   Median :40.82   Median : -3.7892   Median :  98  
 Mean   : 0.00444   Mean   :38.93   Mean   : -4.5345   Mean   : 318  
 3rd Qu.: 0.00000   3rd Qu.:42.18   3rd Qu.:  0.0406   3rd Qu.: 609  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2371  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax            tmin         precip            nevada 
 Min.   : 2.000   Min.   :226.0   Min.   :111   Min.   :  0.000   Min.   :0  
 1st Qu.: 7.000   1st Qu.:280.0   1st Qu.:173   1st Qu.:  0.000   1st Qu.:0  
 Median : 8.000   Median :301.0   Median :188   Median :  1.000   Median :0  
 Mean   : 7.597   Mean   :300.9   Mean   :187   Mean   :  5.038   Mean   :0  
 3rd Qu.: 8.000   3rd Qu.:321.0   3rd Qu.:203   3rd Qu.:  6.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254   Max.   :320.000   Max.   :0  
   prof_nieve           longitud        latitud            altitud      
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:0.0000000   1st Qu.:36.85   1st Qu.: -5.8792   1st Qu.:  25.0  
 Median :0.0000000   Median :38.88   Median : -2.9553   Median :  68.6  
 Mean   :0.0001273   Mean   :37.82   Mean   : -3.7804   Mean   : 211.6  
 3rd Qu.:0.0000000   3rd Qu.:40.82   3rd Qu.:  0.4942   3rd Qu.: 412.0  
 Max.   :2.0000000   Max.   :43.56   Max.   :  4.2156   Max.   :1167.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

VisualizaciĂ³n de 6 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=6)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=6)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 87.0   Min.   : 20.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.:185.0   1st Qu.: 85.00   1st Qu.:  6.00   1st Qu.:0  
 Median : 5.000   Median :199.0   Median : 99.00   Median : 14.00   Median :0  
 Mean   : 6.613   Mean   :199.6   Mean   : 97.74   Mean   : 19.25   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:215.0   3rd Qu.:111.00   3rd Qu.: 26.00   3rd Qu.:0  
 Max.   :12.000   Max.   :265.0   Max.   :157.00   Max.   :279.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:37.96   1st Qu.: -5.6156   1st Qu.:  32.0  
 Median : 0.00000   Median :40.66   Median : -2.9553   Median :  98.0  
 Mean   : 0.02868   Mean   :39.80   Mean   : -3.0701   Mean   : 339.7  
 3rd Qu.: 0.00000   3rd Qu.:42.08   3rd Qu.:  0.4914   3rd Qu.: 570.8  
 Max.   :38.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2519.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   :109.0   Min.   :-31.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 2.000   1st Qu.:146.0   1st Qu.: 49.00   1st Qu.:  6.00   1st Qu.:0  
 Median : 4.000   Median :158.0   Median : 62.00   Median : 16.00   Median :0  
 Mean   : 5.631   Mean   :158.3   Mean   : 61.56   Mean   : 22.21   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:170.0   3rd Qu.: 74.00   3rd Qu.: 30.00   3rd Qu.:0  
 Max.   :12.000   Max.   :250.0   Max.   :115.00   Max.   :371.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   : 0.00000   Min.   :28.31   Min.   :-16.4992   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:39.47   1st Qu.: -5.6156   1st Qu.:  44.0  
 Median : 0.00000   Median :41.22   Median : -2.9056   Median : 185.0  
 Mean   : 0.05081   Mean   :40.61   Mean   : -2.7805   Mean   : 374.7  
 3rd Qu.: 0.00000   3rd Qu.:42.44   3rd Qu.:  0.5706   3rd Qu.: 611.0  
 Max.   :59.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin            precip      
 Min.   : 1.000   Min.   : 20.0   Min.   :-80.00   Min.   :  0.00  
 1st Qu.: 1.000   1st Qu.: 89.0   1st Qu.: -1.00   1st Qu.:  5.00  
 Median : 3.000   Median :108.0   Median : 17.00   Median : 13.00  
 Mean   : 5.575   Mean   :104.8   Mean   : 15.14   Mean   : 19.43  
 3rd Qu.:11.000   3rd Qu.:123.0   3rd Qu.: 33.00   3rd Qu.: 26.00  
 Max.   :12.000   Max.   :199.0   Max.   : 76.00   Max.   :309.00  
     nevada           prof_nieve          longitud        latitud        
 Min.   :0.000000   Min.   :   0.000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0.000000   1st Qu.:   0.000   1st Qu.:40.66   1st Qu.: -4.6800  
 Median :0.000000   Median :   0.000   Median :41.59   Median : -3.1642  
 Mean   :0.001653   Mean   :   1.347   Mean   :40.95   Mean   : -2.9478  
 3rd Qu.:0.000000   3rd Qu.:   0.000   3rd Qu.:42.36   3rd Qu.:  0.3056  
 Max.   :6.000000   Max.   :1494.000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.: 445.0  
 Median : 687.0  
 Mean   : 804.8  
 3rd Qu.: 945.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax              tmin             precip      
 Min.   : 1.000   Min.   :-53.000   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 2.000   1st Qu.: -4.000   1st Qu.: -65.00   1st Qu.: 17.00  
 Median : 3.000   Median : 11.000   Median : -51.00   Median : 33.00  
 Mean   : 4.798   Mean   :  8.683   Mean   : -54.46   Mean   : 38.67  
 3rd Qu.:11.000   3rd Qu.: 23.000   3rd Qu.: -41.00   3rd Qu.: 54.00  
 Max.   :12.000   Max.   : 75.000   Max.   : -20.00   Max.   :180.00  
     nevada    prof_nieve         longitud        latitud         
 Min.   :0   Min.   :   0.00   Min.   :28.31   Min.   :-16.49920  
 1st Qu.:0   1st Qu.:   0.00   1st Qu.:42.18   1st Qu.:  0.73170  
 Median :0   Median :   0.00   Median :42.47   Median :  0.98440  
 Mean   :0   Mean   :  26.19   Mean   :42.12   Mean   :  0.01983  
 3rd Qu.:0   3rd Qu.:   0.00   3rd Qu.:42.64   3rd Qu.:  1.36560  
 Max.   :0   Max.   :1834.00   Max.   :42.85   Max.   :  2.43780  
    altitud    
 Min.   : 162  
 1st Qu.:1894  
 Median :2247  
 Mean   :2165  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt          tmax            tmin         precip           nevada 
 Min.   : 1.00   Min.   :173.0   Min.   : 57   Min.   :  0.00   Min.   :0  
 1st Qu.: 6.00   1st Qu.:226.0   1st Qu.:127   1st Qu.:  3.00   1st Qu.:0  
 Median : 7.00   Median :246.0   Median :141   Median :  9.00   Median :0  
 Mean   : 7.18   Mean   :246.3   Mean   :140   Mean   : 13.15   Mean   :0  
 3rd Qu.: 9.00   3rd Qu.:267.0   3rd Qu.:156   3rd Qu.: 18.00   3rd Qu.:0  
 Max.   :12.00   Max.   :336.0   Max.   :195   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.: 0.00000   1st Qu.:37.26   1st Qu.: -6.2567   1st Qu.:  32  
 Median : 0.00000   Median :40.82   Median : -3.7892   Median :  98  
 Mean   : 0.00444   Mean   :38.93   Mean   : -4.5345   Mean   : 318  
 3rd Qu.: 0.00000   3rd Qu.:42.18   3rd Qu.:  0.0406   3rd Qu.: 609  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2371  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax            tmin         precip            nevada 
 Min.   : 2.000   Min.   :226.0   Min.   :111   Min.   :  0.000   Min.   :0  
 1st Qu.: 7.000   1st Qu.:280.0   1st Qu.:173   1st Qu.:  0.000   1st Qu.:0  
 Median : 8.000   Median :301.0   Median :188   Median :  1.000   Median :0  
 Mean   : 7.597   Mean   :300.9   Mean   :187   Mean   :  5.038   Mean   :0  
 3rd Qu.: 8.000   3rd Qu.:321.0   3rd Qu.:203   3rd Qu.:  6.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :254   Max.   :320.000   Max.   :0  
   prof_nieve           longitud        latitud            altitud      
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.:0.0000000   1st Qu.:36.85   1st Qu.: -5.8792   1st Qu.:  25.0  
 Median :0.0000000   Median :38.88   Median : -2.9553   Median :  68.6  
 Mean   :0.0001273   Mean   :37.82   Mean   : -3.7804   Mean   : 211.6  
 3rd Qu.:0.0000000   3rd Qu.:40.82   3rd Qu.:  0.4942   3rd Qu.: 412.0  
 Max.   :2.0000000   Max.   :43.56   Max.   :  4.2156   Max.   :1167.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

VisualizaciĂ³n de 8 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=8)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=8)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 87.0   Min.   : 20.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.:185.0   1st Qu.: 85.00   1st Qu.:  6.00   1st Qu.:0  
 Median : 5.000   Median :199.0   Median : 99.00   Median : 14.00   Median :0  
 Mean   : 6.613   Mean   :199.6   Mean   : 97.74   Mean   : 19.25   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:215.0   3rd Qu.:111.00   3rd Qu.: 26.00   3rd Qu.:0  
 Max.   :12.000   Max.   :265.0   Max.   :157.00   Max.   :279.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:37.96   1st Qu.: -5.6156   1st Qu.:  32.0  
 Median : 0.00000   Median :40.66   Median : -2.9553   Median :  98.0  
 Mean   : 0.02868   Mean   :39.80   Mean   : -3.0701   Mean   : 339.7  
 3rd Qu.: 0.00000   3rd Qu.:42.08   3rd Qu.:  0.4914   3rd Qu.: 570.8  
 Max.   :38.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2519.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   :109.0   Min.   :-31.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 2.000   1st Qu.:146.0   1st Qu.: 49.00   1st Qu.:  6.00   1st Qu.:0  
 Median : 4.000   Median :158.0   Median : 62.00   Median : 16.00   Median :0  
 Mean   : 5.631   Mean   :158.3   Mean   : 61.56   Mean   : 22.21   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:170.0   3rd Qu.: 74.00   3rd Qu.: 30.00   3rd Qu.:0  
 Max.   :12.000   Max.   :250.0   Max.   :115.00   Max.   :371.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   : 0.00000   Min.   :28.31   Min.   :-16.4992   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:39.47   1st Qu.: -5.6156   1st Qu.:  44.0  
 Median : 0.00000   Median :41.22   Median : -2.9056   Median : 185.0  
 Mean   : 0.05081   Mean   :40.61   Mean   : -2.7805   Mean   : 374.7  
 3rd Qu.: 0.00000   3rd Qu.:42.44   3rd Qu.:  0.5706   3rd Qu.: 611.0  
 Max.   :59.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin           precip   
 Min.   : 1.000   Min.   : 74.0   Min.   :-35.0   Min.   :  0  
 1st Qu.: 2.000   1st Qu.:113.0   1st Qu.: 18.0   1st Qu.:  6  
 Median : 3.000   Median :122.0   Median : 32.0   Median : 14  
 Mean   : 5.645   Mean   :122.5   Mean   : 29.6   Mean   : 21  
 3rd Qu.:11.000   3rd Qu.:131.0   3rd Qu.: 42.0   3rd Qu.: 28  
 Max.   :12.000   Max.   :199.0   Max.   : 76.0   Max.   :280  
     nevada            prof_nieve         longitud        latitud        
 Min.   :0.0000000   Min.   : 0.0000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0.0000000   1st Qu.: 0.0000   1st Qu.:40.48   1st Qu.: -4.6992  
 Median :0.0000000   Median : 0.0000   Median :41.57   Median : -3.1642  
 Mean   :0.0004625   Mean   : 0.1183   Mean   :41.04   Mean   : -2.8891  
 3rd Qu.:0.0000000   3rd Qu.: 0.0000   3rd Qu.:42.40   3rd Qu.:  0.3264  
 Max.   :2.0000000   Max.   :65.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.: 263.0  
 Median : 567.0  
 Mean   : 638.7  
 3rd Qu.: 790.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax             tmin               precip      
 Min.   : 1.000   Min.   : 20.00   Min.   :-80.00000   Min.   :  0.00  
 1st Qu.: 1.000   1st Qu.: 74.00   1st Qu.:-13.00000   1st Qu.:  5.00  
 Median : 2.000   Median : 89.00   Median :  2.00000   Median : 12.00  
 Mean   : 5.502   Mean   : 86.25   Mean   :  0.04525   Mean   : 17.78  
 3rd Qu.:12.000   3rd Qu.:100.00   3rd Qu.: 15.00000   3rd Qu.: 24.00  
 Max.   :12.000   Max.   :164.00   Max.   : 45.00000   Max.   :309.00  
     nevada           prof_nieve          longitud        latitud       
 Min.   :0.000000   Min.   :   0.000   Min.   :28.31   Min.   :-16.499  
 1st Qu.:0.000000   1st Qu.:   0.000   1st Qu.:40.70   1st Qu.: -4.680  
 Median :0.000000   Median :   0.000   Median :41.60   Median : -3.164  
 Mean   :0.002896   Mean   :   2.628   Mean   :40.86   Mean   : -3.009  
 3rd Qu.:0.000000   3rd Qu.:   0.000   3rd Qu.:42.36   3rd Qu.: -1.008  
 Max.   :6.000000   Max.   :1494.000   Max.   :43.54   Max.   :  3.166  
    altitud    
 Min.   :   2  
 1st Qu.: 617  
 Median : 846  
 Mean   : 978  
 3rd Qu.:1082  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax              tmin             precip      
 Min.   : 1.000   Min.   :-53.000   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 2.000   1st Qu.: -4.000   1st Qu.: -65.00   1st Qu.: 17.00  
 Median : 3.000   Median : 11.000   Median : -51.00   Median : 33.00  
 Mean   : 4.798   Mean   :  8.683   Mean   : -54.46   Mean   : 38.67  
 3rd Qu.:11.000   3rd Qu.: 23.000   3rd Qu.: -41.00   3rd Qu.: 54.00  
 Max.   :12.000   Max.   : 75.000   Max.   : -20.00   Max.   :180.00  
     nevada    prof_nieve         longitud        latitud         
 Min.   :0   Min.   :   0.00   Min.   :28.31   Min.   :-16.49920  
 1st Qu.:0   1st Qu.:   0.00   1st Qu.:42.18   1st Qu.:  0.73170  
 Median :0   Median :   0.00   Median :42.47   Median :  0.98440  
 Mean   :0   Mean   :  26.19   Mean   :42.12   Mean   :  0.01983  
 3rd Qu.:0   3rd Qu.:   0.00   3rd Qu.:42.64   3rd Qu.:  1.36560  
 Max.   :0   Max.   :1834.00   Max.   :42.85   Max.   :  2.43780  
    altitud    
 Min.   : 162  
 1st Qu.:1894  
 Median :2247  
 Mean   :2165  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt          tmax            tmin         precip           nevada 
 Min.   : 1.00   Min.   :173.0   Min.   : 57   Min.   :  0.00   Min.   :0  
 1st Qu.: 6.00   1st Qu.:226.0   1st Qu.:127   1st Qu.:  3.00   1st Qu.:0  
 Median : 7.00   Median :246.0   Median :141   Median :  9.00   Median :0  
 Mean   : 7.18   Mean   :246.3   Mean   :140   Mean   : 13.15   Mean   :0  
 3rd Qu.: 9.00   3rd Qu.:267.0   3rd Qu.:156   3rd Qu.: 18.00   3rd Qu.:0  
 Max.   :12.00   Max.   :336.0   Max.   :195   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud    
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1  
 1st Qu.: 0.00000   1st Qu.:37.26   1st Qu.: -6.2567   1st Qu.:  32  
 Median : 0.00000   Median :40.82   Median : -3.7892   Median :  98  
 Mean   : 0.00444   Mean   :38.93   Mean   : -4.5345   Mean   : 318  
 3rd Qu.: 0.00000   3rd Qu.:42.18   3rd Qu.:  0.0406   3rd Qu.: 609  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2371  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt           tmax            tmin           precip            nevada 
 Min.   : 2.000   Min.   :226.0   Min.   :173.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 7.000   1st Qu.:262.0   1st Qu.:191.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 8.000   Median :276.0   Median :203.0   Median :  1.000   Median :0  
 Mean   : 7.796   Mean   :277.6   Mean   :202.7   Mean   :  5.093   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:292.0   3rd Qu.:213.0   3rd Qu.:  5.000   3rd Qu.:0  
 Max.   :12.000   Max.   :340.0   Max.   :254.0   Max.   :218.000   Max.   :0  
   prof_nieve           longitud        latitud            altitud       
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.00  
 1st Qu.:0.0000000   1st Qu.:28.63   1st Qu.:-13.8631   1st Qu.:   7.00  
 Median :0.0000000   Median :36.85   Median : -2.4544   Median :  25.00  
 Mean   :0.0002894   Mean   :35.51   Mean   : -5.2987   Mean   :  48.29  
 3rd Qu.:0.0000000   3rd Qu.:39.49   3rd Qu.:  0.7106   3rd Qu.:  44.00  
 Max.   :2.0000000   Max.   :43.56   Max.   :  4.2156   Max.   :1004.00  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax            tmin           precip            nevada 
 Min.   : 5.000   Min.   :280.0   Min.   :111.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 7.000   1st Qu.:303.0   1st Qu.:161.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 7.000   Median :317.0   Median :175.0   Median :  2.000   Median :0  
 Mean   : 7.442   Mean   :319.2   Mean   :174.7   Mean   :  4.995   Mean   :0  
 3rd Qu.: 8.000   3rd Qu.:333.0   3rd Qu.:188.0   3rd Qu.:  7.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :250.0   Max.   :320.000   Max.   :0  
   prof_nieve    longitud        latitud            altitud      
 Min.   :0    Min.   :28.44   Min.   :-17.7550   Min.   :   1.0  
 1st Qu.:0    1st Qu.:37.84   1st Qu.: -4.8458   1st Qu.:  71.0  
 Median :0    Median :39.88   Median : -3.4503   Median : 247.0  
 Mean   :0    Mean   :39.64   Mean   : -2.5883   Mean   : 339.9  
 3rd Qu.:0    3rd Qu.:41.31   3rd Qu.:  0.4731   3rd Qu.: 611.0  
 Max.   :0    Max.   :43.30   Max.   :  4.2156   Max.   :1167.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

VisualizaciĂ³n de 10 clĂºsteres:

if (!empty_nodes) {
  plot(hac, hang=-1, labels=F)
  rect.hclust(hac, k=10)
}

VisualizaciĂ³n de los clĂºsters en el mapa

A quĂ© clĂºster pertenece cada nodo del mapa de kohonen:

if (!empty_nodes) {
  groups <- cutree(hac, k=10)
  plot(model, type="mapping",
    bgcol=c("steelblue1","sienna1","yellowgreen","red","blue","yellow","purple","green","white","#1f77b4", '#ff7f0e', '#2ca02c', '#d62728', '#9467bd', '#8c564b', '#e377c2')[groups],
    shape = "straight", labels = "")
  add.cluster.boundaries(model, clustering=groups)
}

AnĂ¡lisis de las observaciones de cada cluster

if (!empty_nodes) {
  # Asignamos a cada registro su clĂºster
  df$cluster <- groups[model$unit.classif]
}

Nuevos dataframes por cluster

if (!empty_nodes) {
  # Creo nuevos dataframes, uno por cada clĂºster.
  df.cluster01 <- subset(df, cluster==1)
  df.cluster02 <- subset(df, cluster==2)
  df.cluster03 <- subset(df, cluster==3)
  df.cluster04 <- subset(df, cluster==4)
  df.cluster05 <- subset(df, cluster==5)
  df.cluster06 <- subset(df, cluster==6)
  df.cluster07 <- subset(df, cluster==7)
  df.cluster08 <- subset(df, cluster==8)
  df.cluster09 <- subset(df, cluster==9)
  df.cluster10 <- subset(df, cluster==10)

  # Extraigo del dataframe las features.
  df.cluster01 <- select(df.cluster01, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster02 <- select(df.cluster02, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster03 <- select(df.cluster03, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster04 <- select(df.cluster04, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster05 <- select(df.cluster05, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster06 <- select(df.cluster06, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster07 <- select(df.cluster07, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster08 <- select(df.cluster08, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster09 <- select(df.cluster09, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
  df.cluster10 <- select(df.cluster10, fecha_cnt, tmax, tmin, precip, nevada, prof_nieve, longitud, latitud, altitud)
}
if (!empty_nodes) summary(df.cluster01)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   : 87.0   Min.   : 20.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 4.000   1st Qu.:185.0   1st Qu.: 85.00   1st Qu.:  6.00   1st Qu.:0  
 Median : 5.000   Median :199.0   Median : 99.00   Median : 14.00   Median :0  
 Mean   : 6.613   Mean   :199.6   Mean   : 97.74   Mean   : 19.25   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:215.0   3rd Qu.:111.00   3rd Qu.: 26.00   3rd Qu.:0  
 Max.   :12.000   Max.   :265.0   Max.   :157.00   Max.   :279.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   : 0.00000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:37.96   1st Qu.: -5.6156   1st Qu.:  32.0  
 Median : 0.00000   Median :40.66   Median : -2.9553   Median :  98.0  
 Mean   : 0.02868   Mean   :39.80   Mean   : -3.0701   Mean   : 339.7  
 3rd Qu.: 0.00000   3rd Qu.:42.08   3rd Qu.:  0.4914   3rd Qu.: 570.8  
 Max.   :38.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2519.0  
if (!empty_nodes) summary(df.cluster02)
   fecha_cnt           tmax            tmin            precip           nevada 
 Min.   : 1.000   Min.   :109.0   Min.   :-31.00   Min.   :  0.00   Min.   :0  
 1st Qu.: 2.000   1st Qu.:146.0   1st Qu.: 49.00   1st Qu.:  6.00   1st Qu.:0  
 Median : 4.000   Median :158.0   Median : 62.00   Median : 16.00   Median :0  
 Mean   : 5.631   Mean   :158.3   Mean   : 61.56   Mean   : 22.21   Mean   :0  
 3rd Qu.:11.000   3rd Qu.:170.0   3rd Qu.: 74.00   3rd Qu.: 30.00   3rd Qu.:0  
 Max.   :12.000   Max.   :250.0   Max.   :115.00   Max.   :371.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   : 0.00000   Min.   :28.31   Min.   :-16.4992   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:39.47   1st Qu.: -5.6156   1st Qu.:  44.0  
 Median : 0.00000   Median :41.22   Median : -2.9056   Median : 185.0  
 Mean   : 0.05081   Mean   :40.61   Mean   : -2.7805   Mean   : 374.7  
 3rd Qu.: 0.00000   3rd Qu.:42.44   3rd Qu.:  0.5706   3rd Qu.: 611.0  
 Max.   :59.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2535.0  
if (!empty_nodes) summary(df.cluster03)
   fecha_cnt           tmax            tmin           precip   
 Min.   : 1.000   Min.   : 74.0   Min.   :-35.0   Min.   :  0  
 1st Qu.: 2.000   1st Qu.:113.0   1st Qu.: 18.0   1st Qu.:  6  
 Median : 3.000   Median :122.0   Median : 32.0   Median : 14  
 Mean   : 5.645   Mean   :122.5   Mean   : 29.6   Mean   : 21  
 3rd Qu.:11.000   3rd Qu.:131.0   3rd Qu.: 42.0   3rd Qu.: 28  
 Max.   :12.000   Max.   :199.0   Max.   : 76.0   Max.   :280  
     nevada            prof_nieve         longitud        latitud        
 Min.   :0.0000000   Min.   : 0.0000   Min.   :28.31   Min.   :-16.4992  
 1st Qu.:0.0000000   1st Qu.: 0.0000   1st Qu.:40.48   1st Qu.: -4.6992  
 Median :0.0000000   Median : 0.0000   Median :41.57   Median : -3.1642  
 Mean   :0.0004625   Mean   : 0.1183   Mean   :41.04   Mean   : -2.8891  
 3rd Qu.:0.0000000   3rd Qu.: 0.0000   3rd Qu.:42.40   3rd Qu.:  0.3264  
 Max.   :2.0000000   Max.   :65.0000   Max.   :43.57   Max.   :  4.2156  
    altitud      
 Min.   :   1.0  
 1st Qu.: 263.0  
 Median : 567.0  
 Mean   : 638.7  
 3rd Qu.: 790.0  
 Max.   :2535.0  
if (!empty_nodes) summary(df.cluster04)
   fecha_cnt           tmax             tmin               precip      
 Min.   : 1.000   Min.   : 20.00   Min.   :-80.00000   Min.   :  0.00  
 1st Qu.: 1.000   1st Qu.: 74.00   1st Qu.:-13.00000   1st Qu.:  5.00  
 Median : 2.000   Median : 89.00   Median :  2.00000   Median : 12.00  
 Mean   : 5.502   Mean   : 86.25   Mean   :  0.04525   Mean   : 17.78  
 3rd Qu.:12.000   3rd Qu.:100.00   3rd Qu.: 15.00000   3rd Qu.: 24.00  
 Max.   :12.000   Max.   :164.00   Max.   : 45.00000   Max.   :309.00  
     nevada           prof_nieve          longitud        latitud       
 Min.   :0.000000   Min.   :   0.000   Min.   :28.31   Min.   :-16.499  
 1st Qu.:0.000000   1st Qu.:   0.000   1st Qu.:40.70   1st Qu.: -4.680  
 Median :0.000000   Median :   0.000   Median :41.60   Median : -3.164  
 Mean   :0.002896   Mean   :   2.628   Mean   :40.86   Mean   : -3.009  
 3rd Qu.:0.000000   3rd Qu.:   0.000   3rd Qu.:42.36   3rd Qu.: -1.008  
 Max.   :6.000000   Max.   :1494.000   Max.   :43.54   Max.   :  3.166  
    altitud    
 Min.   :   2  
 1st Qu.: 617  
 Median : 846  
 Mean   : 978  
 3rd Qu.:1082  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster05)
   fecha_cnt           tmax              tmin             precip      
 Min.   : 1.000   Min.   :-53.000   Min.   :-121.00   Min.   :  0.00  
 1st Qu.: 2.000   1st Qu.: -4.000   1st Qu.: -65.00   1st Qu.: 17.00  
 Median : 3.000   Median : 11.000   Median : -51.00   Median : 33.00  
 Mean   : 4.798   Mean   :  8.683   Mean   : -54.46   Mean   : 38.67  
 3rd Qu.:11.000   3rd Qu.: 23.000   3rd Qu.: -41.00   3rd Qu.: 54.00  
 Max.   :12.000   Max.   : 75.000   Max.   : -20.00   Max.   :180.00  
     nevada    prof_nieve         longitud        latitud         
 Min.   :0   Min.   :   0.00   Min.   :28.31   Min.   :-16.49920  
 1st Qu.:0   1st Qu.:   0.00   1st Qu.:42.18   1st Qu.:  0.73170  
 Median :0   Median :   0.00   Median :42.47   Median :  0.98440  
 Mean   :0   Mean   :  26.19   Mean   :42.12   Mean   :  0.01983  
 3rd Qu.:0   3rd Qu.:   0.00   3rd Qu.:42.64   3rd Qu.:  1.36560  
 Max.   :0   Max.   :1834.00   Max.   :42.85   Max.   :  2.43780  
    altitud    
 Min.   : 162  
 1st Qu.:1894  
 Median :2247  
 Mean   :2165  
 3rd Qu.:2400  
 Max.   :2535  
if (!empty_nodes) summary(df.cluster06)
   fecha_cnt           tmax          tmin           precip           nevada 
 Min.   : 1.000   Min.   :173   Min.   :123.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 5.000   1st Qu.:209   1st Qu.:141.0   1st Qu.:  2.00   1st Qu.:0  
 Median : 7.000   Median :221   Median :153.0   Median : 10.00   Median :0  
 Mean   : 6.967   Mean   :221   Mean   :152.7   Mean   : 15.65   Mean   :0  
 3rd Qu.:10.000   3rd Qu.:233   3rd Qu.:164.0   3rd Qu.: 22.00   3rd Qu.:0  
 Max.   :12.000   Max.   :255   Max.   :195.0   Max.   :422.00   Max.   :0  
   prof_nieve          longitud        latitud           altitud    
 Min.   :0.000000   Min.   :27.82   Min.   :-17.889   Min.   :   1  
 1st Qu.:0.000000   1st Qu.:28.48   1st Qu.:-15.389   1st Qu.:  21  
 Median :0.000000   Median :37.78   Median : -5.642   Median :  35  
 Mean   :0.001196   Mean   :36.52   Mean   : -7.333   Mean   : 133  
 3rd Qu.:0.000000   3rd Qu.:43.31   3rd Qu.: -2.039   3rd Qu.:  87  
 Max.   :3.000000   Max.   :43.57   Max.   :  4.216   Max.   :2371  
if (!empty_nodes) summary(df.cluster07)
   fecha_cnt           tmax            tmin           precip            nevada 
 Min.   : 2.000   Min.   :226.0   Min.   :173.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 7.000   1st Qu.:262.0   1st Qu.:191.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 8.000   Median :276.0   Median :203.0   Median :  1.000   Median :0  
 Mean   : 7.796   Mean   :277.6   Mean   :202.7   Mean   :  5.093   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:292.0   3rd Qu.:213.0   3rd Qu.:  5.000   3rd Qu.:0  
 Max.   :12.000   Max.   :340.0   Max.   :254.0   Max.   :218.000   Max.   :0  
   prof_nieve           longitud        latitud            altitud       
 Min.   :0.0000000   Min.   :27.82   Min.   :-17.8889   Min.   :   1.00  
 1st Qu.:0.0000000   1st Qu.:28.63   1st Qu.:-13.8631   1st Qu.:   7.00  
 Median :0.0000000   Median :36.85   Median : -2.4544   Median :  25.00  
 Mean   :0.0002894   Mean   :35.51   Mean   : -5.2987   Mean   :  48.29  
 3rd Qu.:0.0000000   3rd Qu.:39.49   3rd Qu.:  0.7106   3rd Qu.:  44.00  
 Max.   :2.0000000   Max.   :43.56   Max.   :  4.2156   Max.   :1004.00  
if (!empty_nodes) summary(df.cluster08)
   fecha_cnt           tmax            tmin           precip           nevada 
 Min.   : 1.000   Min.   :226.0   Min.   : 57.0   Min.   :  0.00   Min.   :0  
 1st Qu.: 5.000   1st Qu.:240.0   1st Qu.:108.0   1st Qu.:  4.00   1st Qu.:0  
 Median : 7.000   Median :248.0   Median :123.0   Median : 10.00   Median :0  
 Mean   : 7.222   Mean   :248.5   Mean   :120.4   Mean   : 13.05   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:256.0   3rd Qu.:134.0   3rd Qu.: 18.00   3rd Qu.:0  
 Max.   :12.000   Max.   :296.0   Max.   :151.0   Max.   :190.00   Max.   :0  
   prof_nieve          longitud        latitud            altitud      
 Min.   : 0.00000   Min.   :27.92   Min.   :-16.5606   Min.   :   1.0  
 1st Qu.: 0.00000   1st Qu.:39.48   1st Qu.: -5.6000   1st Qu.:  81.0  
 Median : 0.00000   Median :41.11   Median : -2.9056   Median : 415.0  
 Mean   : 0.01309   Mean   :40.57   Mean   : -2.8921   Mean   : 446.1  
 3rd Qu.: 0.00000   3rd Qu.:42.24   3rd Qu.:  0.3264   3rd Qu.: 704.0  
 Max.   :35.00000   Max.   :43.57   Max.   :  4.2156   Max.   :2371.0  
if (!empty_nodes) summary(df.cluster09)
   fecha_cnt           tmax            tmin           precip            nevada 
 Min.   : 5.000   Min.   :280.0   Min.   :111.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 7.000   1st Qu.:303.0   1st Qu.:161.0   1st Qu.:  0.000   1st Qu.:0  
 Median : 7.000   Median :317.0   Median :175.0   Median :  2.000   Median :0  
 Mean   : 7.442   Mean   :319.2   Mean   :174.7   Mean   :  4.995   Mean   :0  
 3rd Qu.: 8.000   3rd Qu.:333.0   3rd Qu.:188.0   3rd Qu.:  7.000   3rd Qu.:0  
 Max.   :12.000   Max.   :403.0   Max.   :250.0   Max.   :320.000   Max.   :0  
   prof_nieve    longitud        latitud            altitud      
 Min.   :0    Min.   :28.44   Min.   :-17.7550   Min.   :   1.0  
 1st Qu.:0    1st Qu.:37.84   1st Qu.: -4.8458   1st Qu.:  71.0  
 Median :0    Median :39.88   Median : -3.4503   Median : 247.0  
 Mean   :0    Mean   :39.64   Mean   : -2.5883   Mean   : 339.9  
 3rd Qu.:0    3rd Qu.:41.31   3rd Qu.:  0.4731   3rd Qu.: 611.0  
 Max.   :0    Max.   :43.30   Max.   :  4.2156   Max.   :1167.0  
if (!empty_nodes) summary(df.cluster10)
   fecha_cnt           tmax            tmin           precip            nevada 
 Min.   : 3.000   Min.   :251.0   Min.   : 91.0   Min.   :  0.000   Min.   :0  
 1st Qu.: 6.000   1st Qu.:269.0   1st Qu.:129.0   1st Qu.:  2.000   1st Qu.:0  
 Median : 7.000   Median :277.0   Median :144.0   Median :  7.000   Median :0  
 Mean   : 7.417   Mean   :277.6   Mean   :142.9   Mean   :  9.946   Mean   :0  
 3rd Qu.: 9.000   3rd Qu.:286.0   3rd Qu.:157.0   3rd Qu.: 14.000   3rd Qu.:0  
 Max.   :12.000   Max.   :336.0   Max.   :177.0   Max.   :132.000   Max.   :0  
   prof_nieve    longitud        latitud            altitud      
 Min.   :0    Min.   :27.92   Min.   :-16.5606   Min.   :   1.0  
 1st Qu.:0    1st Qu.:39.47   1st Qu.: -4.8500   1st Qu.:  81.0  
 Median :0    Median :40.96   Median : -2.4831   Median : 442.0  
 Mean   :0    Mean   :40.44   Mean   : -2.4996   Mean   : 432.9  
 3rd Qu.:0    3rd Qu.:41.84   3rd Qu.:  0.4914   3rd Qu.: 704.0  
 Max.   :0    Max.   :43.43   Max.   :  4.2156   Max.   :2371.0  

NĂºmero de elementos en cada clĂºster

if (!empty_nodes) {
  df.clusters.dim <- c(dim(df.cluster01)[1], dim(df.cluster02)[1], dim(df.cluster03)[1], dim(df.cluster04)[1], dim(df.cluster05)[1], dim(df.cluster06)[1], dim(df.cluster07)[1], dim(df.cluster08)[1], dim(df.cluster09)[1], dim(df.cluster10)[1])
  barplot(df.clusters.dim,
          names.arg = c("cluster01", "cluster02", "cluster03", "cluster04", "cluster05", "cluster06", "cluster07", "cluster08", "cluster09", "cluster10"),
          col = "steelblue1")
}

DistribuciĂ³n de los datos

if (!empty_nodes) mpr.hist(df.cluster01)

if (!empty_nodes) mpr.hist(df.cluster02)

if (!empty_nodes) mpr.hist(df.cluster03)

if (!empty_nodes) mpr.hist(df.cluster04)

if (!empty_nodes) mpr.hist(df.cluster05)

if (!empty_nodes) mpr.hist(df.cluster06)

if (!empty_nodes) mpr.hist(df.cluster07)

if (!empty_nodes) mpr.hist(df.cluster08)

if (!empty_nodes) mpr.hist(df.cluster09)

if (!empty_nodes) mpr.hist(df.cluster10)

if (!empty_nodes) mpr.boxplot(df.cluster01)
if (!empty_nodes) mpr.boxplot(df.cluster02)

if (!empty_nodes) mpr.boxplot(df.cluster03)

if (!empty_nodes) mpr.boxplot(df.cluster04)

if (!empty_nodes) mpr.boxplot(df.cluster05)

if (!empty_nodes) mpr.boxplot(df.cluster06)

if (!empty_nodes) mpr.boxplot(df.cluster07)

if (!empty_nodes) mpr.boxplot(df.cluster08)

if (!empty_nodes) mpr.boxplot(df.cluster09)

if (!empty_nodes) mpr.boxplot(df.cluster10)

LocalizaciĂ³n geogrĂ¡fica de las estaciones de medida de cada cluster

# Agrupa por longitud y latitud para rellenar el mapa con menos datos.
if (!empty_nodes) {
  df.cluster01.grouped <- mpr.group_by_geo(df.cluster01)
  df.cluster02.grouped <- mpr.group_by_geo(df.cluster02)
  df.cluster03.grouped <- mpr.group_by_geo(df.cluster03)
  df.cluster04.grouped <- mpr.group_by_geo(df.cluster04)
  df.cluster05.grouped <- mpr.group_by_geo(df.cluster05)
  df.cluster06.grouped <- mpr.group_by_geo(df.cluster06)
  df.cluster07.grouped <- mpr.group_by_geo(df.cluster07)
  df.cluster08.grouped <- mpr.group_by_geo(df.cluster08)
  df.cluster09.grouped <- mpr.group_by_geo(df.cluster09)
  df.cluster10.grouped <- mpr.group_by_geo(df.cluster10)
}
if (!empty_nodes) mpr.draw_map(spain, df.cluster01.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster02.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster03.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster04.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster05.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster06.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster07.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster08.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster09.grouped)

if (!empty_nodes) mpr.draw_map(spain, df.cluster10.grouped)

LS0tCnRpdGxlOiAiQW7DoWxpc2lzIGRlIG1vZGVsb3MgU09NIC0gRnJlY3VlbmNpYSBkYXRvcyBkZSBlbnRyYWRhOiBtZXMiCm91dHB1dDogaHRtbF9ub3RlYm9vawotLS0KCiMgTW9kZWxvCgoqIElEOiAzNjkKKiBEZXNjcmlwY2nDs246IAoqIEZyZWN1ZW5jaWE6IG1lcwoqIFZhcmlhYmxlczogdG1heCwgdG1pbgoqIERpbWVuc2lvbmVzIGRlbCBtYXBhOiA1LDUKKiBJdGVyYWNpb25lczogMTAwMAoqIFBhcsOhbWV0cm9zIGFkaWNpb25hbGVzOiAKCmBgYHtyfQpzb3VyY2UoIi4uLy4uL2xpYi9zb20tdXRpbHMuUiIpCnNvdXJjZSgiLi4vLi4vbGliL21hcHMtdXRpbHMuUiIpCmBgYAoKIyBDYXJnYSBkZWwgbW9kZWxvIGRlc2RlIGRpc2NvCgpgYGB7cn0KbXByLnNldF9iYXNlX3BhdGhfYW5hbHlzaXMoKQptb2RlbCA8LSBtcHIubG9hZF9tb2RlbCgic29tLTM2OS5yZHMueHoiKQpzdW1tYXJ5KG1vZGVsKQpgYGAKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJjaGFuZ2VzIikKYGBgCgojIENhcmdhIGRlbCBkYXRhc2V0IGRlIGVudHJhZGEKCmBgYHtyfQpkZiA8LSBtcHIubG9hZF9kYXRhKCJkYXRvc19tZXMuY3N2Lnh6IikKYGBgCgpgYGB7cn0KZGYKYGBgCgpgYGB7cn0Kc3VtbWFyeShkZikKYGBgCgojIENhcmdhIGRlIGxvcyBtYXBhcwoKYGBge3J9CndvcmxkIDwtIG5lX2NvdW50cmllcyhzY2FsZSA9ICJtZWRpdW0iLCByZXR1cm5jbGFzcyA9ICJzZiIpCnNwYWluIDwtIHN1YnNldCh3b3JsZCwgYWRtaW4gPT0gIlNwYWluIikKYGBgCgojIE1hcGEgZGUgZGVuc2lkYWQKCmBgYHtyfQpwbG90KG1vZGVsLCB0eXBlPSJjb3VudCIsIHNoYXBlID0gInN0cmFpZ2h0IiwgcGFsZXR0ZS5uYW1lID0gbXByLmRlZ3JhZGUuYmxldSkKYGBgCgpOw7ptZXJvIGRlIGVsZW1lbnRvcyBlbiBjYWRhIGNlbGRhOgoKYGBge3J9Cm5iIDwtIHRhYmxlKG1vZGVsJHVuaXQuY2xhc3NpZikKcHJpbnQobmIpCmBgYApDb21wcm9iYWNpw7NuIGRlIG5vZG9zIHZhY8Otb3M6CgpgYGB7cn0KZGltX21vZGVsIDwtIDUqNTsKbGVuX25iID0gbGVuZ3RoKG5iKTsKZW1wdHlfbm9kZXMgPC0gZGltX21vZGVsICE9IGxlbl9uYjsKaWYgKGVtcHR5X25vZGVzKSB7CiAgcHJpbnQocGFzdGUoIltXYXJuaW5nXSBFeGlzdGVuIG5vZG9zIHZhY8Otb3M6ICIsIGxlbl9uYiwgIi8iLCBkaW1fbW9kZWwpKQp9CmBgYAoKIyBNYXBhIGRlIGRpc3RhbmNpYSBlbnRyZSB2ZWNpbm9zCgpgYGB7cn0KcGxvdChtb2RlbCwgdHlwZT0iZGlzdC5uZWlnaGJvdXJzIiwgc2hhcGUgPSAic3RyYWlnaHQiKQpgYGAKCiMgSW5mbHVlbmNpYSBkZSBsYXMgdmFyaWFibGVzCgpgYGB7cn0KbW9kZWxfY29sbmFtZXMgPSBjKCJ0bWF4IiwgInRtaW4iKQptb2RlbF9uY29sID0gbGVuZ3RoKG1vZGVsX2NvbG5hbWVzKQpgYGAKCiMjIE1hcGEgZGUgdmFyaWFibGVzLgoKYGBge3J9CnBsb3QobW9kZWwsIHNoYXBlID0gInN0cmFpZ2h0IikKYGBgCgojIyBNYXBhIGRlIGNhbG9yIHBvciB2YXJpYWJsZQoKYGBge3J9CnBhcihtZnJvdz1jKDMsNCkpCmZvciAoaiBpbiAxOm1vZGVsX25jb2wpIHsKICBwbG90KG1vZGVsLCB0eXBlPSJwcm9wZXJ0eSIsIHByb3BlcnR5PWdldENvZGVzKG1vZGVsLDEpWyxqXSwKICAgIHBhbGV0dGUubmFtZT1tcHIuY29vbEJsdWVIb3RSZWQsCiAgICBtYWluPW1vZGVsX2NvbG5hbWVzW2pdLAogICAgY2V4PTAuNSwgc2hhcGUgPSAic3RyYWlnaHQiKQp9CmBgYAoKIyMgQ29ycmVsYWNpw7NuIHBhcmEgY2FkYSBjb2x1bW5hIGRlbCB2ZWN0b3IgZGUgbm9kb3MKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgY29yIDwtIGFwcGx5KGdldENvZGVzKG1vZGVsLDEpLCAyLCBtcHIud2VpZ2h0ZWQuY29ycmVsYXRpb24sIHc9bmIsIHNvbT1tb2RlbCkKICBwcmludChjb3IpCn0KYGBgCgpSZXByZXNlbnRhY2nDs24gZGUgY2FkYSB2YXJpYWJsZSBlbiB1biBtYXBhIGRlIGZhY3RvcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwYXIobWZyb3c9YygxLDEpKQogIHBsb3QoY29yWzEsXSwgY29yWzIsXSwgeGxpbT1jKC0xLDEpLCB5bGltPWMoLTEsMSksIHR5cGU9Im4iKQogIGxpbmVzKGMoLTEsMSksYygwLDApKQogIGxpbmVzKGMoMCwwKSxjKC0xLDEpKQogIHRleHQoY29yWzEsXSwgY29yWzIsXSwgbGFiZWxzPW1vZGVsX2NvbG5hbWVzLCBjZXg9MC43NSkKICBzeW1ib2xzKDAsMCxjaXJjbGVzPTEsaW5jaGVzPUYsYWRkPVQpCn0KYGBgCgpJbXBvcnRhbmNpYSBkZSBjYWRhIHZhcmlhYmxlIC0gdmFyaWFuemEgcG9uZGVyYWRhIHBvciBlbCB0YW1hw7FvIGRlIGxhIGNlbGRhOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBzaWdtYTIgPC0gc3FydChhcHBseShnZXRDb2Rlcyhtb2RlbCwxKSwyLGZ1bmN0aW9uKHgsZWZmZWN0aWYpCiAgICAge208LXN1bShlZmZlY3RpZiooeC13ZWlnaHRlZC5tZWFuKHgsZWZmZWN0aWYpKV4yKS8oc3VtKGVmZmVjdGlmKS0xKX0sCiAgICAgZWZmZWN0aWY9bmIpKQogIHByaW50KHNvcnQoc2lnbWEyLGRlY3JlYXNpbmc9VCkpCn0KYGBgCgojIENsdXN0ZXJpbmcKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgaGFjIDwtIG1wci5oYWMobW9kZWwsIG5iKQp9CmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgMyBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTMpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0zKQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDQgY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz00KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9NCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNSBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTUpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz01KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQpgYGAKCiMjIyMgTsO6bWVybyBkZSBlbGVtZW50b3MgZW4gY2FkYSBjbMO6c3RlcgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVycy5kaW0gPC0gYyhkaW0oZGYuY2x1c3RlcjAxKVsxXSwgZGltKGRmLmNsdXN0ZXIwMilbMV0sIGRpbShkZi5jbHVzdGVyMDMpWzFdLCBkaW0oZGYuY2x1c3RlcjA0KVsxXSwgZGltKGRmLmNsdXN0ZXIwNSlbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmBgYAoKIyMjIExvY2FsaXphY2nDs24gZ2VvZ3LDoWZpY2EgZGUgbGFzIGVzdGFjaW9uZXMgZGUgbWVkaWRhIGRlIGNhZGEgY2x1c3RlcgoKYGBge3J9CiMgQWdydXBhIHBvciBsb25naXR1ZCB5IGxhdGl0dWQgcGFyYSByZWxsZW5hciBlbCBtYXBhIGNvbiBtZW5vcyBkYXRvcy4KaWYgKCFlbXB0eV9ub2RlcykgewogIGRmLmNsdXN0ZXIwMS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAxKQogIGRmLmNsdXN0ZXIwMi5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAyKQogIGRmLmNsdXN0ZXIwMy5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjAzKQogIGRmLmNsdXN0ZXIwNC5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA0KQogIGRmLmNsdXN0ZXIwNS5ncm91cGVkIDwtIG1wci5ncm91cF9ieV9nZW8oZGYuY2x1c3RlcjA1KQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAxLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAyLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjAzLmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA0Lmdyb3VwZWQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5kcmF3X21hcChzcGFpbiwgZGYuY2x1c3RlcjA1Lmdyb3VwZWQpCmBgYAoKIyMgVmlzdWFsaXphY2nDs24gZGUgNiBjbMO6c3RlcmVzOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBwbG90KGhhYywgaGFuZz0tMSwgbGFiZWxzPUYpCiAgcmVjdC5oY2x1c3QoaGFjLCBrPTYpCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz02KQogIHBsb3QobW9kZWwsIHR5cGU9Im1hcHBpbmciLAogICAgYmdjb2w9Yygic3RlZWxibHVlMSIsInNpZW5uYTEiLCJ5ZWxsb3dncmVlbiIsInJlZCIsImJsdWUiLCJ5ZWxsb3ciLCJwdXJwbGUiLCJncmVlbiIsIndoaXRlIiwiIzFmNzdiNCIsICcjZmY3ZjBlJywgJyMyY2EwMmMnLCAnI2Q2MjcyOCcsICcjOTQ2N2JkJywgJyM4YzU2NGInLCAnI2UzNzdjMicpW2dyb3Vwc10sCiAgICBzaGFwZSA9ICJzdHJhaWdodCIsIGxhYmVscyA9ICIiKQogIGFkZC5jbHVzdGVyLmJvdW5kYXJpZXMobW9kZWwsIGNsdXN0ZXJpbmc9Z3JvdXBzKQp9CmBgYAoKIyMjIEFuw6FsaXNpcyBkZSBsYXMgb2JzZXJ2YWNpb25lcyBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBBc2lnbmFtb3MgYSBjYWRhIHJlZ2lzdHJvIHN1IGNsw7pzdGVyCiAgZGYkY2x1c3RlciA8LSBncm91cHNbbW9kZWwkdW5pdC5jbGFzc2lmXQp9CmBgYAoKTnVldm9zIGRhdGFmcmFtZXMgcG9yIGNsdXN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgIyBDcmVvIG51ZXZvcyBkYXRhZnJhbWVzLCB1bm8gcG9yIGNhZGEgY2zDunN0ZXIuCiAgZGYuY2x1c3RlcjAxIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MSkKICBkZi5jbHVzdGVyMDIgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0yKQogIGRmLmNsdXN0ZXIwMyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTMpCiAgZGYuY2x1c3RlcjA0IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NCkKICBkZi5jbHVzdGVyMDUgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT01KQogIGRmLmNsdXN0ZXIwNiA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTYpCgogICMgRXh0cmFpZ28gZGVsIGRhdGFmcmFtZSBsYXMgZmVhdHVyZXMuCiAgZGYuY2x1c3RlcjAxIDwtIHNlbGVjdChkZi5jbHVzdGVyMDEsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMiA8LSBzZWxlY3QoZGYuY2x1c3RlcjAyLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDMgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA0IDwtIHNlbGVjdChkZi5jbHVzdGVyMDQsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNSA8LSBzZWxlY3QoZGYuY2x1c3RlcjA1LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDYgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCn0KYGBgCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNikKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSkKICBiYXJwbG90KGRmLmNsdXN0ZXJzLmRpbSwKICAgICAgICAgIG5hbWVzLmFyZyA9IGMoImNsdXN0ZXIwMSIsICJjbHVzdGVyMDIiLCAiY2x1c3RlcjAzIiwgImNsdXN0ZXIwNCIsICJjbHVzdGVyMDUiLCAiY2x1c3RlcjA2IiksCiAgICAgICAgICBjb2wgPSAic3RlZWxibHVlMSIpCn0KYGBgCgojIyMjIERpc3RyaWJ1Y2nDs24gZGUgbG9zIGRhdG9zCgpgYGB7ciBmaWcuaGVpZ2h0PTd9CmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDYpCmBgYAoKYGBge3IgZmlnLmhlaWdodD01fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA2KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDggY2zDunN0ZXJlczoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgcGxvdChoYWMsIGhhbmc9LTEsIGxhYmVscz1GKQogIHJlY3QuaGNsdXN0KGhhYywgaz04KQp9CmBgYAoKIyMjIFZpc3VhbGl6YWNpw7NuIGRlIGxvcyBjbMO6c3RlcnMgZW4gZWwgbWFwYQoKQSBxdcOpIGNsw7pzdGVyIHBlcnRlbmVjZSBjYWRhIG5vZG8gZGVsIG1hcGEgZGUga29ob25lbjoKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZ3JvdXBzIDwtIGN1dHJlZShoYWMsIGs9OCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKCiAgIyBFeHRyYWlnbyBkZWwgZGF0YWZyYW1lIGxhcyBmZWF0dXJlcy4KICBkZi5jbHVzdGVyMDEgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAyIDwtIHNlbGVjdChkZi5jbHVzdGVyMDIsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwMyA8LSBzZWxlY3QoZGYuY2x1c3RlcjAzLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDQgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA1IDwtIHNlbGVjdChkZi5jbHVzdGVyMDUsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNiA8LSBzZWxlY3QoZGYuY2x1c3RlcjA2LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDcgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNywgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA4IDwtIHNlbGVjdChkZi5jbHVzdGVyMDgsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQp9CmBgYAoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwOCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdKQogIGJhcnBsb3QoZGYuY2x1c3RlcnMuZGltLAogICAgICAgICAgbmFtZXMuYXJnID0gYygiY2x1c3RlcjAxIiwgImNsdXN0ZXIwMiIsICJjbHVzdGVyMDMiLCAiY2x1c3RlcjA0IiwgImNsdXN0ZXIwNSIsICJjbHVzdGVyMDYiLCAiY2x1c3RlcjA3IiwgImNsdXN0ZXIwOCIpLAogICAgICAgICAgY29sID0gInN0ZWVsYmx1ZTEiKQp9CmBgYAoKIyMjIyBEaXN0cmlidWNpw7NuIGRlIGxvcyBkYXRvcwoKYGBge3IgZmlnLmhlaWdodD03fQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDEpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDQpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDcpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOCkKYGBgCgpgYGB7ciBmaWcuaGVpZ2h0PTV9CmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAyKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDMpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA1KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDYpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA4KQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQpgYGAKCiMjIFZpc3VhbGl6YWNpw7NuIGRlIDEwIGNsw7pzdGVyZXM6CgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogIHBsb3QoaGFjLCBoYW5nPS0xLCBsYWJlbHM9RikKICByZWN0LmhjbHVzdChoYWMsIGs9MTApCn0KYGBgCgojIyMgVmlzdWFsaXphY2nDs24gZGUgbG9zIGNsw7pzdGVycyBlbiBlbCBtYXBhCgpBIHF1w6kgY2zDunN0ZXIgcGVydGVuZWNlIGNhZGEgbm9kbyBkZWwgbWFwYSBkZSBrb2hvbmVuOgoKYGBge3J9CmlmICghZW1wdHlfbm9kZXMpIHsKICBncm91cHMgPC0gY3V0cmVlKGhhYywgaz0xMCkKICBwbG90KG1vZGVsLCB0eXBlPSJtYXBwaW5nIiwKICAgIGJnY29sPWMoInN0ZWVsYmx1ZTEiLCJzaWVubmExIiwieWVsbG93Z3JlZW4iLCJyZWQiLCJibHVlIiwieWVsbG93IiwicHVycGxlIiwiZ3JlZW4iLCJ3aGl0ZSIsIiMxZjc3YjQiLCAnI2ZmN2YwZScsICcjMmNhMDJjJywgJyNkNjI3MjgnLCAnIzk0NjdiZCcsICcjOGM1NjRiJywgJyNlMzc3YzInKVtncm91cHNdLAogICAgc2hhcGUgPSAic3RyYWlnaHQiLCBsYWJlbHMgPSAiIikKICBhZGQuY2x1c3Rlci5ib3VuZGFyaWVzKG1vZGVsLCBjbHVzdGVyaW5nPWdyb3VwcykKfQpgYGAKCiMjIyBBbsOhbGlzaXMgZGUgbGFzIG9ic2VydmFjaW9uZXMgZGUgY2FkYSBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQXNpZ25hbW9zIGEgY2FkYSByZWdpc3RybyBzdSBjbMO6c3RlcgogIGRmJGNsdXN0ZXIgPC0gZ3JvdXBzW21vZGVsJHVuaXQuY2xhc3NpZl0KfQpgYGAKCk51ZXZvcyBkYXRhZnJhbWVzIHBvciBjbHVzdGVyCgpgYGB7cn0KaWYgKCFlbXB0eV9ub2RlcykgewogICMgQ3JlbyBudWV2b3MgZGF0YWZyYW1lcywgdW5vIHBvciBjYWRhIGNsw7pzdGVyLgogIGRmLmNsdXN0ZXIwMSA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEpCiAgZGYuY2x1c3RlcjAyIDwtIHN1YnNldChkZiwgY2x1c3Rlcj09MikKICBkZi5jbHVzdGVyMDMgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT0zKQogIGRmLmNsdXN0ZXIwNCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTQpCiAgZGYuY2x1c3RlcjA1IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09NSkKICBkZi5jbHVzdGVyMDYgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT02KQogIGRmLmNsdXN0ZXIwNyA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTcpCiAgZGYuY2x1c3RlcjA4IDwtIHN1YnNldChkZiwgY2x1c3Rlcj09OCkKICBkZi5jbHVzdGVyMDkgPC0gc3Vic2V0KGRmLCBjbHVzdGVyPT05KQogIGRmLmNsdXN0ZXIxMCA8LSBzdWJzZXQoZGYsIGNsdXN0ZXI9PTEwKQoKICAjIEV4dHJhaWdvIGRlbCBkYXRhZnJhbWUgbGFzIGZlYXR1cmVzLgogIGRmLmNsdXN0ZXIwMSA8LSBzZWxlY3QoZGYuY2x1c3RlcjAxLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDIgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwMiwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjAzIDwtIHNlbGVjdChkZi5jbHVzdGVyMDMsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNCA8LSBzZWxlY3QoZGYuY2x1c3RlcjA0LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDUgPC0gc2VsZWN0KGRmLmNsdXN0ZXIwNSwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA2IDwtIHNlbGVjdChkZi5jbHVzdGVyMDYsIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIwNyA8LSBzZWxlY3QoZGYuY2x1c3RlcjA3LCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKICBkZi5jbHVzdGVyMDggPC0gc2VsZWN0KGRmLmNsdXN0ZXIwOCwgZmVjaGFfY250LCB0bWF4LCB0bWluLCBwcmVjaXAsIG5ldmFkYSwgcHJvZl9uaWV2ZSwgbG9uZ2l0dWQsIGxhdGl0dWQsIGFsdGl0dWQpCiAgZGYuY2x1c3RlcjA5IDwtIHNlbGVjdChkZi5jbHVzdGVyMDksIGZlY2hhX2NudCwgdG1heCwgdG1pbiwgcHJlY2lwLCBuZXZhZGEsIHByb2ZfbmlldmUsIGxvbmdpdHVkLCBsYXRpdHVkLCBhbHRpdHVkKQogIGRmLmNsdXN0ZXIxMCA8LSBzZWxlY3QoZGYuY2x1c3RlcjEwLCBmZWNoYV9jbnQsIHRtYXgsIHRtaW4sIHByZWNpcCwgbmV2YWRhLCBwcm9mX25pZXZlLCBsb25naXR1ZCwgbGF0aXR1ZCwgYWx0aXR1ZCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwMSkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjAzKQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNCkKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA2KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIwNykKaWYgKCFlbXB0eV9ub2Rlcykgc3VtbWFyeShkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIHN1bW1hcnkoZGYuY2x1c3RlcjA5KQppZiAoIWVtcHR5X25vZGVzKSBzdW1tYXJ5KGRmLmNsdXN0ZXIxMCkKYGBgCgojIyMjIE7Dum1lcm8gZGUgZWxlbWVudG9zIGVuIGNhZGEgY2zDunN0ZXIKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSB7CiAgZGYuY2x1c3RlcnMuZGltIDwtIGMoZGltKGRmLmNsdXN0ZXIwMSlbMV0sIGRpbShkZi5jbHVzdGVyMDIpWzFdLCBkaW0oZGYuY2x1c3RlcjAzKVsxXSwgZGltKGRmLmNsdXN0ZXIwNClbMV0sIGRpbShkZi5jbHVzdGVyMDUpWzFdLCBkaW0oZGYuY2x1c3RlcjA2KVsxXSwgZGltKGRmLmNsdXN0ZXIwNylbMV0sIGRpbShkZi5jbHVzdGVyMDgpWzFdLCBkaW0oZGYuY2x1c3RlcjA5KVsxXSwgZGltKGRmLmNsdXN0ZXIxMClbMV0pCiAgYmFycGxvdChkZi5jbHVzdGVycy5kaW0sCiAgICAgICAgICBuYW1lcy5hcmcgPSBjKCJjbHVzdGVyMDEiLCAiY2x1c3RlcjAyIiwgImNsdXN0ZXIwMyIsICJjbHVzdGVyMDQiLCAiY2x1c3RlcjA1IiwgImNsdXN0ZXIwNiIsICJjbHVzdGVyMDciLCAiY2x1c3RlcjA4IiwgImNsdXN0ZXIwOSIsICJjbHVzdGVyMTAiKSwKICAgICAgICAgIGNvbCA9ICJzdGVlbGJsdWUxIikKfQpgYGAKCiMjIyMgRGlzdHJpYnVjacOzbiBkZSBsb3MgZGF0b3MKCmBgYHtyIGZpZy5oZWlnaHQ9N30KaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuaGlzdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5oaXN0KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmhpc3QoZGYuY2x1c3RlcjEwKQpgYGAKCmBgYHtyIGZpZy5oZWlnaHQ9NX0KaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjAxKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDIpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwMykKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA0KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDUpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwNikKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjA3KQppZiAoIWVtcHR5X25vZGVzKSBtcHIuYm94cGxvdChkZi5jbHVzdGVyMDgpCmlmICghZW1wdHlfbm9kZXMpIG1wci5ib3hwbG90KGRmLmNsdXN0ZXIwOSkKaWYgKCFlbXB0eV9ub2RlcykgbXByLmJveHBsb3QoZGYuY2x1c3RlcjEwKQpgYGAKCiMjIyBMb2NhbGl6YWNpw7NuIGdlb2dyw6FmaWNhIGRlIGxhcyBlc3RhY2lvbmVzIGRlIG1lZGlkYSBkZSBjYWRhIGNsdXN0ZXIKCmBgYHtyfQojIEFncnVwYSBwb3IgbG9uZ2l0dWQgeSBsYXRpdHVkIHBhcmEgcmVsbGVuYXIgZWwgbWFwYSBjb24gbWVub3MgZGF0b3MuCmlmICghZW1wdHlfbm9kZXMpIHsKICBkZi5jbHVzdGVyMDEuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMSkKICBkZi5jbHVzdGVyMDIuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMikKICBkZi5jbHVzdGVyMDMuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwMykKICBkZi5jbHVzdGVyMDQuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNCkKICBkZi5jbHVzdGVyMDUuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNSkKICBkZi5jbHVzdGVyMDYuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNikKICBkZi5jbHVzdGVyMDcuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwNykKICBkZi5jbHVzdGVyMDguZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOCkKICBkZi5jbHVzdGVyMDkuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIwOSkKICBkZi5jbHVzdGVyMTAuZ3JvdXBlZCA8LSBtcHIuZ3JvdXBfYnlfZ2VvKGRmLmNsdXN0ZXIxMCkKfQpgYGAKCmBgYHtyfQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwMy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNi5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwNy5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOC5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIwOS5ncm91cGVkKQppZiAoIWVtcHR5X25vZGVzKSBtcHIuZHJhd19tYXAoc3BhaW4sIGRmLmNsdXN0ZXIxMC5ncm91cGVkKQpgYGAK